package org.example.thread.chapterIV;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 等待/通知经典范式
 * synchronized(对象){
 * while(条件不满足){
 * 对象.wait();
 * }
 * // 对应的处理逻辑
 * }
 * <p>
 * synchronized(对象){
 * 改变条件
 * 对象.notifyAll();
 * }
 */
public class WaitNotify {
    static boolean flag = true;
    static Object lock = new Object();

    public static void main(String[] args) throws InterruptedException {
//        new Thread(new Wait(), "WaitThread").start();
        new Thread(new WaitTime(1000), "WaitTimeThread").start();
        TimeUnit.SECONDS.sleep(3);
        new Thread(new Notify(), "NotifyThread").start();

    }


    static class Wait implements Runnable {
        @Override
        public void run() {
            // 加锁，拥有lock的Monitor
            synchronized (lock) {
                // 条件不满足时，继续wait.同时释放了lock锁
                while (flag) {
                    try {
                        System.out.println(Thread.currentThread() + " flag is true. wait @" +
                                new SimpleDateFormat("HH:mm:ss").format(new Date()));
                        // wait(1) 超时时间设置
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // 条件满足时，完成工作
                System.out.println(Thread.currentThread() + "flag is false. running @"
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            }
        }
    }

    static class WaitTime implements Runnable {
        private long time;

        public WaitTime(long time) {
            this.time = time;
        }

        @Override
        public void run() {
            // 加锁，拥有lock的Monitor
            synchronized (lock) {
                // 条件不满足时，继续wait.同时释放了lock锁
                while (flag) {
                    try {
                        System.out.println(Thread.currentThread() + " flag is true. wait @" +
                                new SimpleDateFormat("HH:mm:ss").format(new Date()));
                        lock.wait(time);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // 条件满足时，完成工作
                System.out.println(Thread.currentThread() + "flag is false. running @"
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            }
        }
    }


    static class Notify implements Runnable {
        @Override
        public void run() {
            // 获取lock的锁，然后进行通知，通知时不会释放lock的锁
            // 直到当前线程释放了lock后，WaitThread 才能从wait方法中返回
            synchronized (lock) {
                System.out.println(Thread.currentThread() + "hold lock. notify @" +
                        new SimpleDateFormat("HH:mm:ss").format(new Date()));
                // notify 的线程释放锁之后，等待线程才有机会从wait()返回
                lock.notifyAll();
                flag = false;
                SleepUtils.second(5);
            }
            // 再次加锁
            synchronized (lock) {
                System.out.println(Thread.currentThread() + "hold lock again. sleep @" +
                        new SimpleDateFormat("HH:mm:ss").format(new Date()));
                SleepUtils.second(5);
            }
        }
    }
}
